package robot

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"

	"device-admin/config/mysql"
	"device-admin/config/redis"
	"device-admin/internal/app/grpc/protoc/robotc"
	"device-admin/internal/app/grpc/service/alarm_monitor"
	"device-admin/internal/app/grpc/service/common"
	"device-admin/internal/app/web/service/device"
	"device-admin/internal/define"
	"device-admin/internal/models"

	"192.168.1.75/go-pkg/go-cache"
	"192.168.1.75/go-pkg/logx"
	"github.com/shopspring/decimal"
	"google.golang.org/protobuf/proto"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var errLogger = logger.New(
	log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
	logger.Config{
		SlowThreshold:             time.Second,  // 慢 SQL 阈值
		LogLevel:                  logger.Error, // 日志级别
		IgnoreRecordNotFoundError: true,         // 忽略ErrRecordNotFound（记录未找到）错误
		Colorful:                  true,         // 禁用彩色打印
	},
)

var deviceRegistered = make(map[string]bool)

// RobotBaseStatus2Server 设备基础信息
// 暂时仅用到当前任务名称
func (s *Server) RobotBaseStatus2Server(ctx context.Context, data *robotc.NotifyTaskStatus) (*robotc.RspTaskStatus, error) {
	currentTaskName := data.GetStrCurrentTaskName()
	cache.HSet(define.CacheRobotRTInfo+GetRobotID(ctx), "current_task_name", string(currentTaskName), 0, nil)
	return &robotc.RspTaskStatus{NVoid: 1}, nil
}

// 设备状态处理
func robotStatusHandle(ctx context.Context, robotStatusData *robotc.NotifyRobotStatus) {
	robotID := string(robotStatusData.GetMetaData().GetStrRobotID())
	if robotID == "" {
		logx.Error(context.Background(), "NotifyRobotStatus2Server,robot can not be empty", logx.String("robot_id", robotID))
		return
	}

	// 缓存状态
	cache.HSet(define.CacheRobotRTInfo+robotID, "robot_status", robotStatusData, 0, nil)

	// 缓存电量
	batteryPercent, _ := decimal.NewFromFloat32(robotStatusData.GetBatteryState().GetPercent()).Truncate(1).Float64()
	cache.HSet(define.CacheRobotRTInfo+robotID, "system_battery", fmt.Sprintf("%.1f", batteryPercent), 0, nil)

	// 缓存模式
	mode := robotStatusData.GetNavState().GetMode()
	subMode := robotStatusData.GetNavState().GetSubMode()

	// 当模式发生变化时，缓存至redis队列
	// 模式定义：
	// 1：运营任务 2: 手动充电 3：自动充电 4：待命模式 5：出坞 6：回坞 7：寻找充电桩
	UpdateDeviceRunMode(robotID)

	// 低电量检查
	lowBatteryCheck(robotID, int(batteryPercent))

	// 实时状态本地缓存
	cache.HSet(define.CacheRobotRTInfo+robotID, "mode", int(mode), 0, nil)
	cache.HSet(define.CacheRobotRTInfo+robotID, "sub_mode", int(subMode), 0, nil)
	cache.HSet(define.CacheRobotRTInfo+robotID, "position_x", robotStatusData.GetNavState().GetPose().GetX(), 0, nil)
	cache.HSet(define.CacheRobotRTInfo+robotID, "position_y", robotStatusData.GetNavState().GetPose().GetY(), 0, nil)
	cache.HSet(define.CacheRobotRTInfo+robotID, "position_direction", robotStatusData.GetNavState().GetPose().GetTh(), 0, nil)
	// 更新活跃时间以及正在使用的地图
	// 更新地图最近的使用时间
	db := mysql.NewDB().Session(&gorm.Session{Logger: errLogger})
	{
		value, found := cache.HGet(define.CacheRobotRTInfo+robotID, "current_map_name")
		currentMapName, _ := value.(string)
		if !found || currentMapName != robotStatusData.GetNavState().GetCurMapName() {
			db.Model(&models.Device{}).
				Where("robot_id = ?", robotID).
				Updates(&models.Device{
					LatestActiveTime: time.Now().Unix(),
					CurrentMapName:   robotStatusData.GetNavState().GetCurMapName(),
				})
			db.Model(&models.DeviceMap{}).
				Where("robot_id = ?", robotID).
				Where("map_name = ?", robotStatusData.GetNavState().GetCurMapName()).
				Where("deleted_at = ?", 0).
				Updates(&models.DeviceMap{
					UsedAt: time.Now().Unix(),
				})
		}
		// 缓存当前使用的地图
		cache.HSet(define.CacheRobotRTInfo+robotID, "current_map_name", robotStatusData.GetNavState().GetCurMapName(), 0, nil)
	}

	// 设备注册
	// 仅在设备首次上报信息时进行注册检查
	{
		if !deviceRegistered[robotID] {
			// 注册设备
			deviceRegistered[robotID] = true
			// 延迟时间
			r := rand.New(rand.NewSource(time.Now().UnixNano()))
			second := r.Intn(30)
			// 延迟函数
			time.AfterFunc(time.Second*time.Duration(second), func() {
				var count int64
				db.Model(&models.Device{}).Where("robot_id = ? ", robotID).Count(&count)
				if count <= 0 {
					// 自动添加设备
					db.Model(&models.Device{}).Create(&models.Device{
						RobotID:            robotID,
						IdentificationCode: string(robotStatusData.GetMetaData().GetStrRobotIDCard()),
						DeviceType:         int(robotStatusData.GetMetaData().GetEnDeviceType().Number()),
						LatestActiveTime:   time.Now().Unix(),
						MerchantID:         "1", // 默认属于admin
						MerchantPath:       ">1",
					})
				}
				// 保存架构信息
				arch := robotStatusData.GetMetaData().GetNPlatformArchitecture()
				db.Model(&models.Terminal{}).
					Where("robot_id = ?", robotID).
					Where("terminal_type = ?", "95").
					Updates(map[string]interface{}{
						"arch": int(arch),
					})
			})

		}
	}
	// 实时全局缓存
	// 地图名称，设备的位置
	{
		rdb := redis.NewDB()
		// 设备当前使用的地图
		currentMapSrcVal, _ := cache.HGet(define.CacheRobotRTInfo+robotID, "current_map_src_"+robotStatusData.GetNavState().GetCurMapName())
		currentMapSrc, _ := currentMapSrcVal.(string)
		rctx, rcancel := context.WithTimeout(context.Background(), time.Second*3)
		defer rcancel()
		rdb.HSet(rctx, define.RedisRobotRTMap+robotID,
			"name", robotStatusData.GetNavState().GetCurMapName(),
			"url", currentMapSrc,
		)
		// 设备当前的位置
		x0 := robotStatusData.GetNavState().GetPose().GetX()
		y0 := robotStatusData.GetNavState().GetPose().GetY()
		if dataVal, found := cache.HGet(define.CacheRobotRTInfo+robotID, robotStatusData.GetNavState().GetCurMapName()+"_affine_data"); found {
			data, _ := dataVal.([]byte)
			affineData := &robotc.AffineMat{}
			if err := proto.Unmarshal(data, affineData); err == nil {
				px := int(x0*affineData.GetR11() + y0*affineData.GetR12() + affineData.GetTx())
				py := int(x0*affineData.GetR21() + y0*affineData.GetR22() + affineData.GetTy())
				rdb.HSet(rctx, define.RedisRobotRtPosition+robotID,
					"px", px,
					"py", py,
				)
				rdb.Expire(rctx, define.RedisRobotRtPosition+robotID, time.Second*60)
			}
		}
	}

	// 发布实时信息
	{
		go PublishRobotRealtimeInfo(ctx, "status")
	}
}

// NotifyRobotStatus2Server 上报机器人基本信息
// 机器人标识，机器人环境因子，导航定位信息（GNSS_Info为计算后的信息），当前的位置信息等
func (s *Server) NotifyRobotStatus2Server(ctx context.Context, data *robotc.NotifyRobotStatus) (*robotc.RspNotifyRobotStatus, error) {
	// robotStatusHandle(ctx, data)
	// 返回结果
	return &robotc.RspNotifyRobotStatus{NVoid: 0}, nil
}

// GetSurviveInfoC2Srsp 机器人存活信息上报响应
func (s *Server) GetSurviveInfoC2Srsp(ctx context.Context, data *robotc.RspGetSurviveInfoClient2Server) (*robotc.ReqGetSurviveInfoServer2Client, error) {
	surviveInfoHandle(ctx, data)
	return &robotc.ReqGetSurviveInfoServer2Client{}, nil
}

// surviveInfoHandle 活跃信息处理
func surviveInfoHandle(ctx context.Context, data *robotc.RspGetSurviveInfoClient2Server) {
	robotID := GetRobotID(ctx)

	// 保存设备运行数据的更新时间
	func() {
		redisCtx, redisCancel := context.WithTimeout(context.Background(), time.Second*3)
		defer redisCancel()
		redis.NewDB().HSet(redisCtx, define.RedisTaskDataUpdatedAt, robotID, time.Now().Unix())
	}()

	// 统计每天的运行里程及运行时长
	activeDurations := []models.DeviceActiveDuration{}
	surviveInfos := data.GetData()
	for _, surviveInfo := range surviveInfos {
		activeDuration := models.DeviceActiveDuration{}
		year := strconv.Itoa(int(surviveInfo.GetYear()))
		month := strconv.Itoa(int(surviveInfo.GetMon()))
		day := strconv.Itoa(int(surviveInfo.GetDay()))
		activeDuration.Date = strings.Join([]string{year, month, day}, "-")
		liveDatas := surviveInfo.GetLiveData()
		activeDuration.ChargingDuration = surviveInfo.GetChargingTimeSec()
		activeDuration.IdleDuration = surviveInfo.GetIdleTimeSec()
		for _, liveData := range liveDatas {
			activeDuration.RunningOdometer += liveData.GetEndTimeOdometer() - liveData.GetStartTimeOdometer()
			activeDuration.RunningDuration += liveData.GetEndTimestamp() - liveData.GetStartTimestamp()
		}
		activeDuration.RobotID = robotID
		activeDurations = append(activeDurations, activeDuration)
	}
	device.SyncActiveDuration(activeDurations)
}

// GetDDRAlarmInfoC2Srsp 机器人告警信息
// 实时告警信息，会保存到数据库，并在web客户端socket连接时，推送到客户端
func (s *Server) GetDDRAlarmInfoC2Srsp(ctx context.Context, data *robotc.RspGetDDRAlarmInfoClient2Server) (*robotc.ReqGetDDRAlarmInfoServer2Client, error) {
	ddrAlarmInfoHandle(ctx, data)
	return &robotc.ReqGetDDRAlarmInfoServer2Client{}, nil
}

// ddrAlarmInfoHandle 告警信息处理
func ddrAlarmInfoHandle(ctx context.Context, alarmInfo *robotc.RspGetDDRAlarmInfoClient2Server) {
	robotID := GetRobotID(ctx)
	if robotID == "" {
		return
	}
	// 发布实时数据
	{
		dataBytes, _ := proto.Marshal(alarmInfo)
		// 缓存在redis,可以通过redis pub/sub模式通知websocket客户端
		cache.HSet(define.CacheRobotRTInfo+GetRobotID(ctx), "alarm_info", dataBytes, 0, nil)
	}
}

// PublishRobotRealtimeInfo 利用redis发布机器人实时状态信息
// 直接从redis缓存中获取
func PublishRobotRealtimeInfo(ctx context.Context, _ string) {
	robotID := GetRobotID(ctx)
	redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
	defer redisCtxCancel()
	// 频率限制，前后两次须等待1s
	// _, wait := cache.Get(define.CacheRTInfoPubWait + robotID)
	// if !wait {
	// 置位等待
	cache.Set(define.CacheRTInfoPubWait+robotID, 1, time.Second*1, nil)
	// 从缓存中获取数据缓存
	robotRealtimeInfo := GetRealtimeInfo(robotID)
	// 实时状态信息，有订阅时才发布
	{
		sub, _ := redis.NewDB().Exists(redisCtx, define.RedisRobotRTInfoSubFlag+robotID).Result()
		if sub > 0 {
			// 发布消息
			robotRealtimeInfoBytes, err := json.Marshal(robotRealtimeInfo)
			if err == nil {
				// 发布设备实时信息
				ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
				defer cancel()
				redis.NewDB().Publish(ctx, define.RedisRobotRTInfo+robotID, robotRealtimeInfoBytes)
			}
		}
	}
	// 实时告警信息，有订阅时才发布
	{
		alarmsub, _ := redis.NewDB().Exists(redisCtx, define.RedisRobotRTAlarmInfoSubFlag+robotID).Result()
		if alarmsub > 0 {
			// 仅获取告警信息
			if alarmInfoInterface, ok := robotRealtimeInfo["alarm_info"]; ok {
				alarmInfo := []map[string]interface{}{}
				// 断言，拿到具体告警类型数组
				if alarmInfoArr, ok := alarmInfoInterface.([]map[string]interface{}); ok {
					// 过滤告警字段
					for _, v := range alarmInfoArr {
						item := make(map[string]interface{})
						item["alarm_type"] = v["alarm_type"]
						item["alarm_type_name"] = v["alarm_type_name"]
						item["reported_at"] = v["reported_at"]
						item["created_at"] = v["created_at"]
						alarmInfo = append(alarmInfo, item)
					}
					// 基础信息
					baseInfo := make(map[string]interface{})
					baseInfo["robot_id"] = robotID
					// 组合返给前端的设备告警内容
					// robotID + alarmInfo
					robotRealtimeAlarmInfo := make(map[string]interface{})
					robotRealtimeAlarmInfo["base_info"] = baseInfo
					robotRealtimeAlarmInfo["alarm_info"] = alarmInfo
					// json序列化
					robotRealtimeInfoBytes, err := json.Marshal(robotRealtimeAlarmInfo)
					if err == nil && len(alarmInfo) > 0 {
						// 发布设备实时信息
						ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
						defer cancel()
						redis.NewDB().Publish(ctx, define.RedisRobotRTAlarmInfo+robotID, robotRealtimeInfoBytes)
					}
				}
			}
		}
	}
	// }
}

// GetRealtimeInfo 获取实时状态信息
func GetRealtimeInfo(robotID string) map[string]interface{} {
	robotRealtimeInfo := make(map[string]interface{})
	currentMap := ""
	if data, found := cache.HGet(define.CacheRobotRTInfo+robotID, "robot_status"); found {
		if notifyRobotStatus, ok := data.(*robotc.NotifyRobotStatus); ok {
			deviceType := int(notifyRobotStatus.MetaData.GetEnDeviceType().Number())
			currentMapSrcVal, _ := cache.HGet(define.CacheRobotRTInfo+robotID, "current_map_src_"+notifyRobotStatus.GetNavState().GetCurMapName())
			currentMapSrc, _ := currentMapSrcVal.(string)
			currentMap = notifyRobotStatus.GetNavState().GetCurMapName()
			currentTaskName, _ := cache.HGet(define.CacheRobotRTInfo+robotID, "current_task_name")
			// 保存充电状态
			ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
			defer cancel()
			if notifyRobotStatus.GetNavState().GetMode() == 6 ||
				notifyRobotStatus.BatteryState.Bcharging ||
				notifyRobotStatus.GetGPIOState().GetRchgConnected() > 0 {
				redis.NewDB().HSet(ctx, define.RedisRobotRTMap+robotID, "charging_status", 1)
			} else {
				redis.NewDB().HSet(ctx, define.RedisRobotRTMap+robotID, "charging_status", 0)
			}
			// 模式显示
			subModeName := define.NavSubMode[int(notifyRobotStatus.GetNavState().SubMode)]
			// 判断是自动充电还是线充
			if notifyRobotStatus.GetGPIOState().GetRchgConnected() > 0 {
				if notifyRobotStatus.GetBatteryState().GetBcharging() {
					subModeName = "线充充电模式，正在充电"
				} else {
					subModeName = "线充充电模式，未充电"
				}
			} else {
				if notifyRobotStatus.GetBatteryState().GetBcharging() {
					if notifyRobotStatus.GetNavState().GetMode() == robotc.NavStateEMode(robotc.NavState_SWITCH) {
						subModeName = "处于模式切换中"
					} else if notifyRobotStatus.GetNavState().GetMode() == robotc.NavStateEMode(robotc.NavState_RCHG) {
						subModeName = "自动充电模式，正在充电"
					} else {
						subModeName = "线充充电模式，正在充电"
					}
				}
			}
			robotRealtimeInfo["base_info"] = map[string]interface{}{
				"robot_id":          string(notifyRobotStatus.GetMetaData().GetStrRobotID()),
				"robot_id_card":     string(notifyRobotStatus.GetMetaData().GetStrRobotIDCard()),
				"device_type":       deviceType,
				"device_type_name":  define.DeviceType[deviceType],
				"mode":              notifyRobotStatus.GetNavState().GetMode(),
				"mode_name":         define.NavMode[int(notifyRobotStatus.GetNavState().GetMode())],
				"sub_mode":          int(notifyRobotStatus.GetNavState().SubMode),
				"sub_mode_name":     subModeName,
				"current_map_name":  notifyRobotStatus.GetNavState().GetCurMapName(),
				"current_map_src":   currentMapSrc,
				"location_res":      notifyRobotStatus.GetNavState().GetBLocated(), // 定位结果
				"location_info":     notifyRobotStatus.GetSysInfoLocation(),        // 定位状态，true-已定位
				"current_task_name": currentTaskName,
				"update_map_status": notifyRobotStatus.GetUpdateMapStatus().GetStatus(), // 地图更新状态
			}
			batteryPercent, _ := decimal.NewFromFloat32(notifyRobotStatus.GetBatteryState().GetPercent()).Truncate(2).Float64()
			batteryVol, _ := decimal.NewFromFloat32(notifyRobotStatus.GetBatteryState().GetVoltage()).Truncate(2).Float64()
			robotRealtimeInfo["system_info"] = map[string]interface{}{
				"time":             notifyRobotStatus.GetSysTimestamp(),
				"cpu":              notifyRobotStatus.GetSysInfoCPU(),
				"cpu_temp":         notifyRobotStatus.GetSysInfoTemp(),
				"mem":              notifyRobotStatus.GetSysInfoMemory(),
				"battery":          batteryPercent,
				"battery_vol":      batteryVol,
				"battery_temp":     notifyRobotStatus.GetBatteryState().GetTemp(),
				"battery_charging": notifyRobotStatus.GetBatteryState().GetBcharging(),
			}
			currentPos := map[string]float64{
				"x":         float64(notifyRobotStatus.GetNavState().GetPose().GetX()),
				"y":         float64(notifyRobotStatus.GetNavState().GetPose().GetY()),
				"direction": float64(notifyRobotStatus.GetNavState().GetPose().GetTh()),
			}
			robotRealtimeInfo["current_pos"] = currentPos
		}
	}

	// 变换矩阵
	if dataVal, found := cache.HGet(define.CacheRobotRTInfo+robotID, currentMap+"_affine_data"); found {
		data, _ := dataVal.([]byte)
		affineData := &robotc.AffineMat{}
		if err := proto.Unmarshal(data, affineData); err == nil {
			affineData := map[string]float32{
				"r11": affineData.GetR11(),
				"r12": affineData.GetR12(),
				"r21": affineData.GetR21(),
				"r22": affineData.GetR22(),
				"tx":  affineData.GetTx(),
				"ty":  affineData.GetTy(),
			}
			robotRealtimeInfo["affine_data"] = affineData
		}
	}

	// 雷达点云
	// base64编码存储
	{
		if data, found := cache.HGet(define.CacheRobotRTInfo+robotID, "obs_data"); found {
			if dataBytes, ok := data.([]byte); ok {
				robotRealtimeInfo["obs_data"] = base64.StdEncoding.EncodeToString(dataBytes)
			}
		}
	}

	// 配置项
	{
		configItem := []map[string]interface{}{}
		OA_OBS_RADIUS := common.GetRobotConfig(robotID, "PPOAC_Params.OA_OBS_RADIUS")
		item := make(map[string]interface{})
		item["key"] = "PPOAC_Params.OA_OBS_RADIUS"
		item["value"] = OA_OBS_RADIUS
		configItem = append(configItem, item)
		robotRealtimeInfo["config_item"] = configItem
	}

	// 超声数据
	{
		if data, found := cache.HGet(define.CacheRobotRTInfo+robotID, "OBSUSIRData"); found {
			if dataBytes, ok := data.([]byte); ok {
				OBSUSIRData := []map[string]interface{}{}
				OBSUSIRDataC2S := &robotc.OBSUSIRDataC2S{}
				err := proto.Unmarshal([]byte(dataBytes), OBSUSIRDataC2S)
				if err == nil {
					OBSUSIRDataC2SArr := OBSUSIRDataC2S.GetData()
					for _, data := range OBSUSIRDataC2SArr {
						item := make(map[string]interface{})
						item["sensor_id"] = data.GetSensorID()
						item["distance"] = data.GetDist()
						item["is_trigger"] = data.GetBIsTrigger()
						OBSUSIRData = append(OBSUSIRData, item)
					}
				}
				robotRealtimeInfo["obs_usir_data"] = OBSUSIRData
			}
		}
	}

	// 实时告警信息
	{
		if data, found := cache.HGet(define.CacheRobotRTInfo+robotID, "alarm_info"); found {
			if dataBytes, ok := data.([]byte); ok {
				alarmInfo := []map[string]interface{}{}
				alarmInfoPb := &robotc.RspGetDDRAlarmInfoClient2Server{}
				err := proto.Unmarshal(dataBytes, alarmInfoPb)
				if err == nil {
					alarmInfoPbData := alarmInfoPb.GetData()
					for _, data := range alarmInfoPbData {
						item := make(map[string]interface{})
						item["alarm_type"] = int(data.GetType())
						item["alarm_type_name"] = define.AlarmType[int(data.GetType())].Name
						item["map_name"] = string(data.GetCurrroute())
						item["pos_x"] = data.GetPosx()
						item["pos_y"] = data.GetPosy()
						item["pos_direction"] = data.GetPosdirection()
						item["detail"] = string(data.GetDetailInfo())
						item["reported_at"] = data.GetTimeStamp() / 1000
						item["created_at"] = data.GetTriggerTimeStamp() / 1000
						alarmInfo = append(alarmInfo, item)
					}
				}
				robotRealtimeInfo["alarm_info"] = alarmInfo
			}
		}
	}
	return robotRealtimeInfo
}

// UpdateDeviceRunMode 更新设备的运行模式

// 模式定义：
// 1.运营任务
// 2.手动充电
// 3.自动充电
// 4.待命模式
// 5.出坞
// 6.回坞。
// 7.寻找充电桩
func UpdateDeviceRunMode(robotID string) {
	workMode := 4 // 当前机器人的业务模式（根据业务定义的），默认为待命模式
	if data, found := cache.HGet(define.CacheRobotRTInfo+robotID, "robot_status"); found {
		if robotStatusData, ok := data.(*robotc.NotifyRobotStatus); ok {
			mode := robotStatusData.GetNavState().GetMode()
			subMode := robotStatusData.GetNavState().GetSubMode()
			oldMode, oldSubMode := 0, 0
			if modeVal, found := cache.HGet(define.CacheRobotRTInfo+robotID, "mode"); found {
				if modeInt, ok := modeVal.(int); ok {
					oldMode = modeInt
				}
			}
			if subModeVal, found := cache.HGet(define.CacheRobotRTInfo+robotID, "sub_mode"); found {
				if subModeInt, ok := subModeVal.(int); ok {
					oldSubMode = subModeInt
				}
			}
			if oldMode != int(mode) || oldSubMode != int(subMode) {
				// 获取任务类型，默认为运营
				var workType = 1
				if val, found := cache.HGet(define.CacheRobotRTInfo+robotID, "work_type"); found {
					if valInt, ok := val.(int); ok {
						workType = valInt
					}
				}
				// 判断运营模式
				{
					if mode == 5 && workType == 1 {
						// 处于运营任务
						workMode = 1
					} else if robotStatusData.GetGPIOState().RchgConnected == 1 || (robotStatusData.BatteryState.GetBcharging() && mode != 6) {
						// 手动充电
						workMode = 2
					} else if mode == 6 && (robotStatusData.BatteryState.GetBcharging() || subMode == 10) {
						// 自动充电
						workMode = 3
					} else if mode == 3 {
						// 待命模式
						workMode = 4
					} else if mode == 5 && workType == 3 {
						// 出坞模式
						workMode = 5
					} else if mode == 5 && workType == 2 {
						// 回坞模式
						workMode = 6
					} else if mode == 6 && subMode == 9 {
						// 寻找充电桩
						workMode = 7
					} else {
						workMode = 4 // 默认待命模式
						logx.Info(context.Background(), "unknown device mode,default idle mode", logx.String("robotID", robotID))
					}
				}
				// 缓存至redis
				ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
				defer cancel()
				redis.NewDB().HSet(ctx, define.RedisRobotRTInfo+robotID, "work_mode", workMode)
			}
		}
	}
}

// lowBatteryCheck 低电量检查
// robotID 设备id,battery 电量
func lowBatteryCheck(robotID string, battery int) {
	lowBatteryTh := common.GetLowBatteryTh(robotID)
	// 获取上次的电量
	oldBattery := common.GetBattery(robotID)
	// 触发低电量告警监测
	if oldBattery > lowBatteryTh && battery <= lowBatteryTh {
		alarm_monitor.AlarmMonitor{}.AddMonitor(robotID, 0x0A, time.Now().Unix(), 1, false, "", "")
	}
	// 保存实时电量
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel()
	redis.NewDB().HSet(ctx, define.RedisRobotRTInfo+robotID, "battery", battery)
}

// DDRConfigHandler 95配置上报处理
func DDRConfigHandler(robotID string, msg *robotc.WildMsg) {
	// 获取自动回充的阈值，作为低电量告警阈值
	rspConfigOperational := &robotc.RspConfigOperational{}
	proto.Unmarshal(msg.BodyContent, rspConfigOperational)
	confDatas := rspConfigOperational.GetData()
	for _, confData := range confDatas {
		coreConf := confData.GetData()
		key := string(coreConf.GetKey())
		val := string(coreConf.GetValue())
		ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
		defer cancel()
		redis.NewDB().HSet(ctx, define.RedisDDRConfig+robotID, key, val)
	}
}
